'''

    A QtextEditDevice changes the input of a given QTextEdit instance
    by routing Qt key events it receives to a KeyGen which will emit
    altered keystrokes.

'''

from PyQt4 import QtGui, QtCore

from SHIK.devices import KeyboardDevice

class _EventFilter(QtCore.QObject):
    def __init__(self, te_device):
        QtCore.QObject.__init__(self, None)
        self._te_device = te_device
        self.enabled = True
    
    def fromKey(self, key):
        seq = QtGui.QKeySequence(key)
        ret = str(seq.toString())
#        print "   ", key, "->", repr(ret)
        return ret
    
    def eventFilter( self, obj, event ):
        if not self.enabled:
            # Bypass the filter
            print "QTE Device not filtering event:", event
            return False
        
        if event.type() == QtCore.QEvent.KeyPress:
#            print 'press event', chr(event.key()), event.isAutoRepeat()
            if not event.isAutoRepeat():
                self._te_device.on_press(self.fromKey(event.key()))
            return True # eat event
        
        if event.type() == QtCore.QEvent.KeyRelease:
#            print 'release event', chr(event.key()), event.isAutoRepeat()
            if not event.isAutoRepeat():
                self._te_device.on_release(self.fromKey(event.key()))
            return True # eat event
        
        return False # let the event live

class QTextEditDevice(KeyboardDevice):
    def __init__(self, qtextedit):
        KeyboardDevice.__init__(self)
        self._event_filter = _EventFilter(self)
        self._te = qtextedit
        qtextedit.installEventFilter(self._event_filter)

    def enable(self, b):
        '''
        Overridden to let the event filter act accordingly.
        '''
        KeyboardDevice.enable(self,b)
        self._event_filter.enabled = b
    
    def DoMove(self, op, CTRL, SHIFT):
        if CTRL:
            op = {
                '{HOME}':     QtGui.QTextCursor.Start,
                '{END}':      QtGui.QTextCursor.End,
                '{LEFT}':     QtGui.QTextCursor.WordLeft,
                '{RIGHT}':    QtGui.QTextCursor.WordRight,
            }.get(op)
        else:
            op = {
                '{HOME}':     QtGui.QTextCursor.StartOfLine,
                '{END}':      QtGui.QTextCursor.EndOfLine,
                '{LEFT}':     QtGui.QTextCursor.Left,
                '{RIGHT}':    QtGui.QTextCursor.Right,
                '{UP}':       QtGui.QTextCursor.Up,
                '{DOWN}':     QtGui.QTextCursor.Down,
                '{PAGEUP}':   QtGui.QTextCursor.PreviousBlock,
                '{PAGEDOWN}': QtGui.QTextCursor.NextBlock,
            }.get(op)
        if op is None:
            print "Move Operation Failed:", op, CTRL, SHIFT
            return
        
        if SHIFT:
            mod = QtGui.QTextCursor.KeepAnchor
        else:
            mod = QtGui.QTextCursor.MoveAnchor

        cursor = self._te.textCursor()
        cursor.movePosition(op, mod)
        self._te.setTextCursor(cursor)
        
    def DoBacspace(self, dummy, CTRL, SHIFT):
        self._te.textCursor().deletePreviousChar()

    def DoCut(self, dummy, CTRL, SHIFT):
        self._te.cut()

    def DoCopy(self, dummy, CTRL, SHIFT):
        self._te.copy()

    def DoPaste(self, dummy, CTRL, SHIFT):
        self._te.paste()

    def DoUndo(self, dummy, CTRL, SHIFT):
        self._te.undo()

    def DoRedo(self, dummy, CTRL, SHIFT):
        self._te.redo()

    def DoAction(self, action, CTRL, SHIFT):
        todo = {
            '{ENTER}':'\n',
            '{BACKSPACE}':self.DoBacspace,
            '{HOME}':self.DoMove,
            '{END}':self.DoMove,
            '{UP}':self.DoMove,
            '{DOWN}':self.DoMove,
            '{LEFT}':self.DoMove,
            '{RIGHT}':self.DoMove,
            '{PAGEUP}':self.DoMove,
            '{PAGEDOWN}':self.DoMove,
            '{CUT}':self.DoCut,
            '{COPY}':self.DoCopy,
            '{PASTE}':self.DoPaste,
            '{UNDO}':self.DoUndo,
            '{REDO}':self.DoUndo,
        }.get(action, None)
        if todo:
            if callable(todo):
                todo(action, CTRL, SHIFT)
            else:
                self.DoSequence(todo, CTRL, SHIFT)

    def DoSequence(self, keys, CTRL, SHIFT):
        if CTRL:
            if SHIFT:
                action = {
                    "z": "{REDO}",
                }.get(keys, None)
            else:
                action = {
                    'x': '{CUT}',
                    'c': '{COPY}',
                    'v': '{PASTE}',
                    'z': '{UNDO}',
                }.get(keys, None)
            if action:
                self.DoAction(action, False, False)
            return
        elif SHIFT:
            keys = keys.upper()
        self._te.insertPlainText(keys)
                
    def emit(self, data):
        print "QTE Device emit:", data
        CTRL = '^' in data
        SHIFT = '+' in data
        data = data.replace('^','')
        data = data.replace('+','')
        if '{' in data:
            self.DoAction(data, CTRL, SHIFT)
        else:
            self.DoSequence(data, CTRL, SHIFT)
        